﻿using UnityEngine;
using System.Collections;
using UniLua;

namespace TCG.FFI
{
	/// <summary>
	/// 导出GameObject给Lua使用。
	/// </summary>
	public static class UnityGameObjectLib  
	{
		#region stuff for exporting to lua
		public static string LIB_NAME = "UnityGameObjectLib";

		public static string ParentLibName = "UnityObjectLib";
		#endregion

		#region static variables
		public static int lf_PrimitiveSphere (ILuaState luaState)
		{
			luaState.PushInteger ((int)PrimitiveType.Sphere);
			return 1;
		}

		public static int lf_PrimitiveCapsule (ILuaState luaState)
		{
			luaState.PushInteger ((int)PrimitiveType.Capsule);
			return 1;
		}

		public static int lf_PrimitiveCylinder (ILuaState luaState)
		{
			luaState.PushInteger ((int)PrimitiveType.Cylinder);
			return 1;
		}

		public static int lf_PrimitiveCube (ILuaState luaState)
		{
			luaState.PushInteger ((int)PrimitiveType.Cube);
			return 1;
		}

		public static int lf_PrimitivePlane (ILuaState luaState)
		{
			luaState.PushInteger ((int)PrimitiveType.Plane);
			return 1;
		}

		public static int lf_PrimitiveQuad (ILuaState luaState)
		{
			luaState.PushInteger ((int)PrimitiveType.Quad);
			return 1;
		}

		#endregion

		#region variables
		public static int mf_IsActiveInHierarchy (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, -1, LIB_NAME) as GameObject;
			luaState.PushBoolean (go.activeInHierarchy);
			return 1;
		}

		public static int mf_IsActiveSelf (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, -1, LIB_NAME) as GameObject;
			luaState.PushBoolean (go.activeSelf);
			return 1;
		}

		public static int mf_GetAnimation (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, -1, LIB_NAME) as GameObject;
			Animation ani = go.animation;
			if (ani == null)
			{
				luaState.PushNil ();
			}
			else
			{
				LuaTools.L_PushUserData (luaState, ani, UnityAnimationLib.LIB_NAME);
			}
			return 1;
		}

		public static int mf_GetAudio (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, -1, LIB_NAME) as GameObject;
			AudioSource audio = go.audio;
			if (audio == null)
			{
				luaState.PushNil ();
			}
			else
			{
				LuaTools.L_PushUserData (luaState, audio, UnityAudioSourceLib.LIB_NAME);
			}

			return 1;
		}

		public static int mf_SetLayer (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			int layer = luaState.ToInteger (2);
			go.layer = layer;
			return 0;
		}

		public static int mf_GetLayer (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			luaState.PushInteger (go.layer);
			return 1;
		}

		public static int mf_GetRender (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, -1, LIB_NAME) as GameObject;
			Renderer render = go.renderer;
			if (render == null)
			{
				luaState.PushNil ();
			}
			else
			{
				LuaTools.L_PushUserData (luaState, render, UnityRectLib.LIB_NAME);
			}
			return 1;
		}

		public static int mf_GetTag (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, -1, LIB_NAME) as GameObject;
			luaState.PushString (go.tag);
			return 1;
		}

		public static int mf_SetTag (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string tag = luaState.ToString (2);
			go.tag = tag;
			return 1;
		}

		public static int mf_GetTransform (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			LuaTools.L_PushUserData (luaState, go.transform, UnityTransformLib.LIB_NAME);
			return 1;
		}

		#endregion

		#region constructors
		public static int lf_NewGameObject (ILuaState luaState)
		{
			GameObject go = new GameObject ();
			if (luaState.GetTop () > 0)
			{
				string name = luaState.ToString (1);
				go.name = name;
			}
			LuaTools.L_PushUserData (luaState, go, LIB_NAME);
			return 1;
		}
		#endregion

		#region functions
		public static int mf_AddComponent (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string className = luaState.ToString (2);
			Component component = go.AddComponent (className);
			LuaTools.L_PushUserData (luaState, component, UnityComponentLib.LIB_NAME);
			return 1;
		}

		public static int mf_BroadcastMessage (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string methodName = luaState.ToString (2);
			object param = null;
			SendMessageOptions option = SendMessageOptions.RequireReceiver;
			if (luaState.GetTop () > 2)
			{
				param = luaState.ToObject (3);
			}

			if (luaState.GetTop () > 3)
			{
				option = (SendMessageOptions) (luaState.ToInteger (4));
			}
			go.BroadcastMessage (methodName, param, option);
			return 0;
		}

		public static int mf_CompareTag (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string tag = luaState.ToString (2);
			luaState.PushBoolean (go.CompareTag (tag));
			return 1;
		}

		public static int mf_GetComponent (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string className = luaState.ToString (2);
			LuaTools.L_PushUserData (luaState, go.GetComponent (className), UnityComponentLib.LIB_NAME);
			return 1;
		}

		public static int mf_GetComponentInChildren (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string className = luaState.ToString (2);
			System.Type type = System.Type.GetType (className);
			LuaTools.L_PushUserData (luaState, go.GetComponentInChildren (type), UnityComponentLib.LIB_NAME);
			return 1;
		}

		public static int mf_GetComponents (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string className = luaState.ToString (2);
			System.Type type = System.Type.GetType (className);
			Component[] components = go.GetComponents (type);
			if (components == null || components.Length == 0)
			{
				luaState.PushNil ();
			}
			else
			{
				luaState.CreateTable (components.Length, 0);
				for (int i = 0, len = components.Length; i < len; ++ i)
				{
					LuaTools.L_PushUserData (luaState, components[i], UnityComponentLib.LIB_NAME);
                    luaState.RawSetI (-2, i + 1);
                }
			}
            
            return 1;
		}

		public static int mf_GetComponentsInChildren (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string className = luaState.ToString (2);
			System.Type type = System.Type.GetType (className);
			Component[] components = go.GetComponentsInChildren (type);
			if (components == null || components.Length == 0)
			{
				luaState.PushNil ();
			}
			else
			{
				luaState.CreateTable (components.Length, 0);
				for (int i = 0, len = components.Length; i < len; ++ i)
				{
					LuaTools.L_PushUserData (luaState, components[i], UnityComponentLib.LIB_NAME);
                    luaState.RawSetI (-2, i + 1);
                }
            }
            
            return 1;
        }

		public static int mf_SendMessage (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string methodName = luaState.ToString (2);
			object param = null;
			SendMessageOptions option = SendMessageOptions.RequireReceiver;
			if (luaState.GetTop () > 2)
			{
				param = luaState.ToObject (3);
			}
			if (luaState.GetTop () > 3)
			{
				option = (SendMessageOptions)(luaState.ToInteger (4));
			}
			go.SendMessage (methodName, param, option);
			return 0;
		}

		public static int mf_SendMessageUpwards (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			string methodName = luaState.ToString (2);
			object param = null;
			SendMessageOptions option = SendMessageOptions.RequireReceiver;
			if (luaState.GetTop () > 2)
			{
				param = luaState.ToObject (3);
			}
			if (luaState.GetTop () > 3)
			{
				option = (SendMessageOptions)(luaState.ToInteger (4));
            }
            go.SendMessageUpwards (methodName, param, option);
            return 0;
		}
        
		public static int mf_SetActive (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			bool active = luaState.ToBoolean (2);
			go.SetActive (active);
			return 0;
		}

        #endregion
        
        #region static functions
		public static int lf_GetGameObject (ILuaState luaState)
		{
			uint prefabId = luaState.ToUnsigned (1);
			int functionRef = luaState.ToInteger (2);

			GameModelPool.instance.GetModel (prefabId, delegate (GameModelPooled model) {
				LuaTools.L_PushUserData (luaState, model.gameObject, LIB_NAME);
				luaState.PushInteger (functionRef);
				LuaTools.CallLuaRefFunction (luaState, functionRef, 2, 0, 0);
			});

			return 0;
		}

		public static int lf_ReleaseGameObject (ILuaState luaState)
		{
			GameObject go = LuaTools.L_CheckUData (luaState, 1, LIB_NAME) as GameObject;
			GameModelPool.instance.ReleaseModel (go.GetComponent<GameModelPooled> ());
			return 0;
		}

		public static int lf_CreatePrimitive (ILuaState luaState)
		{
			PrimitiveType type = (PrimitiveType) (luaState.ToInteger (1));
			LuaTools.L_PushUserData (luaState, GameObject.CreatePrimitive (type), LIB_NAME);
			return 1;
		}

		public static int lf_Find (ILuaState luaState)
		{
			string name = luaState.ToString (1);
			LuaTools.L_PushUserData (luaState, GameObject.Find (name), LIB_NAME);
			return 1;
		}

		public static int lf_FindGameObjectsWithTag (ILuaState luaState)
		{
			string tag = luaState.ToString (1);
			GameObject[] results = GameObject.FindGameObjectsWithTag (tag);
			if (results == null || results.Length == 0)
			{
				luaState.PushNil ();
			}
			else
			{
				luaState.CreateTable (results.Length, 0);
				for (int i = 0, len = results.Length; i < len; ++ i)
				{
					LuaTools.L_PushUserData (luaState, results[i], LIB_NAME);
					luaState.RawSetI (-2, i + 1);
                }
            }
            
            return 1;
        }
        
        public static int lf_FindWithTag (ILuaState luaState)
		{
			string tag = luaState.ToString (1);
			GameObject result = GameObject.FindWithTag (tag);
			if (result == null)
			{
				luaState.PushNil ();
			}
			else
			{
				LuaTools.L_PushUserData (luaState, result, LIB_NAME);
			}

			return 1;
		}

		#endregion

		#region operators

		#endregion
	}
}
